package com.chamei.compiler;

import com.chamei.annotation.ARouter;
import com.chamei.annotation.BindView;
import com.chamei.compiler.utils.Constants;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;

@AutoService(Processor.class)
// 接收的类型
@SupportedAnnotationTypes({Constants.BIND_VIEW_ANNOTATION_TYPES})
// JDK的版本
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class BindViewProcessor extends AbstractProcessor {
    // 操作Element工具类
    private Elements elementsUtils;
    // 打印日志
    private Messager messager;
    // 文件生成器
    private Filer filer;
    private Map<TypeElement,List<Element>> tempBindViewMap = new HashMap<>();

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        // 初始化工作
        elementsUtils = processingEnvironment.getElementUtils();
        messager = processingEnvironment.getMessager();
        filer = processingEnvironment.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if(set.isEmpty()) return false;
        // 获取所有带有ARouter注解的类节点
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(BindView.class);
        if(elements.isEmpty()) return false;
        try{
            // 获取所有有注解类节点和方法节点
            valueOfMap(elements);
            messager.printMessage(Diagnostic.Kind.NOTE,">>>>>>>>>>");
            messager.printMessage(Diagnostic.Kind.NOTE,"size:"+elements.size());
            messager.printMessage(Diagnostic.Kind.NOTE,"<<<<<<<<<<");
            createJavaFile();
        }catch (IOException ioe){
            ioe.printStackTrace();
        }
        return true;
    }

    private void createJavaFile()throws IOException{
        if(tempBindViewMap.isEmpty()) return;
        // 获取接口的类型
        TypeElement viewBindType = elementsUtils.getTypeElement(Constants.VIEW_BINDER);
        for(Map.Entry<TypeElement,List<Element>> entry:tempBindViewMap.entrySet()){
            // 获取类名
            ClassName className = ClassName.get(entry.getKey());
            // 实现接口泛型
            ParameterizedTypeName typeName = ParameterizedTypeName.get(ClassName.get(viewBindType),className);
            // 参数体配置
            ParameterSpec parameterSpec = ParameterSpec.builder(className,Constants.TARGET_PARAMETER_NAME).build();
            // 方法配置
            MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Constants.BIND_METHOD_NAME)
                    .addAnnotation(Override.class)
                    .addModifiers(Modifier.PUBLIC)
                    .addParameter(parameterSpec);
            for(Element fieldElement:entry.getValue()){
                // 获取属性名称
                String fieldName = fieldElement.getSimpleName().toString();
                int annotationValue = fieldElement.getAnnotation(BindView.class).value();
                // 参照 JavaPoet案例
                // $ L 字面量 int value = $L , 10
                // $ S 字符串 $S,"hello"
                // $ N 变量 user.$N Name
                // $ T 接口 $T,MainActivity
                String methodContent = "$N."+fieldName+" = $N.findViewById($L)";
                methodBuilder.addStatement(methodContent,
                        Constants.TARGET_PARAMETER_NAME,
                        Constants.TARGET_PARAMETER_NAME,
                        annotationValue);
            }

            JavaFile.builder(className.packageName(), // 包名
                    TypeSpec.classBuilder(className.simpleName()+"$$ViewBinder")
                            .addSuperinterface(typeName)
                            .addModifiers(Modifier.PUBLIC)
                            .addMethod(methodBuilder.build())
                            .build()
                    ).build().writeTo(filer);
        }
    }


    private void valueOfMap(Set<? extends Element> elements){
        for(Element element:elements){
            TypeElement typeElement = (TypeElement) element.getEnclosingElement();
            if(tempBindViewMap.containsKey(typeElement)){
                tempBindViewMap.get(typeElement).add(element);
            }else{
                List<Element> el = new ArrayList<>();
                el.add(element);
                tempBindViewMap.put(typeElement,el);
            }
        }
    }
}
